package com.wenjiang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.wenjiang.common.constat.RedisKey;
import com.wenjiang.common.dto.OrderParam;
import com.wenjiang.common.exception.SystemBusyException;
import com.wenjiang.common.lang.Result;
import com.wenjiang.common.vo.GoodInfo;
import com.wenjiang.common.vo.OrderInfoVo;
import com.wenjiang.common.vo.PaySuccessVo;
import com.wenjiang.entity.MallComment;
import com.wenjiang.entity.MallOrder;
import com.wenjiang.mapper.MallCommentMapper;
import com.wenjiang.mapper.MallGoodMapper;
import com.wenjiang.mapper.MallOrderMapper;
import com.wenjiang.service.MallCarouselService;
import com.wenjiang.service.MallCommentService;
import com.wenjiang.service.MallOrderService;
import com.wenjiang.util.RedisUtils;
import com.wenjiang.websocket.WebSocketServe;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.weaver.ast.Var;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.redisson.Redisson;
import org.redisson.api.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.rmi.runtime.Log;

import javax.websocket.EncodeException;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lwj
 * @since 2021-07-20
 */
@Service
@Transactional
@Slf4j
public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder> implements MallOrderService {


    @Autowired
    RedisUtils redisUtils;

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    MallOrderMapper mallOrderMapper;

    @Autowired
    MallGoodMapper mallGoodMapper;

    @Autowired
    MallCommentService mallCommentService;

    @Autowired
    WebSocketServe webSocketServe;

    // 注入 分布式锁客户端
    @Autowired
    RedissonClient redissonClient;


    /**
     * 使用redis时 要保证读写操作 都是原子性 (同时 执行 把保证读写都在一个线程)
     * <p>
     * 不然 即时 在java 代码 加入 lock 锁 也没用
     *
     * @param orderParam
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public Result createCartOrder(OrderParam orderParam, String userId) throws RuntimeException {

        //判断订单是否已生成
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(userId);

        // 商品库存不足的id
        String failGoodId=null;

        String[] goodId = orderParam.getGoodId();

        for (String item : goodId) {
            stringBuffer.append(item);
        }
//        if(redisUtils.hasKey(RedisKey.redisOrderKey+stringBuffer.toString())){
//
//            return  Result.fail(200,"你有未支付的订单请先支付,请先支付");
//        }
        //获取所选的商品id和数量
        String goodIds[] = orderParam.getGoodId();


        int num[] = orderParam.getGoodCount();


        //开启事务
        redisTemplate.setEnableTransactionSupport(true);




        //一重判断加入商品已经卖完了



//        try {
//            // 开启事务
//            redisTemplate.multi();
//            redisTemplate.opsForValue().set("rollback", 0);
//            throw new RuntimeException();
//
//        } catch (Exception e){
//            System.out.println("进行回滚");
//            redisTemplate.discard();
//        }finally {
//
//        }
//        redisTemplate.exec();


//        //开启redis 事务
//        redisTemplate.multi();
//        //遍历商品 只要有一个卖完进行回滚
//        redisson.createTransaction()



        //定义分布式锁集合
        List<RLock> rLocks = new ArrayList<>();




//        for (int i=0;i<goodIds.length;i++){
//            //获取商品信息
//            int count = (int) redisTemplate.opsForValue().get(RedisKey.mallGoodCount + goodIds[i]);
//            log.info("商品库存" + count);
//            //判断商品库存是否充足
//            if (count==0||count < num[i]) {
//                 // 设置失败id;
//                failGoodId = goodIds[i];
//                return Result.fail("商品" + failGoodId + "已经卖完了");
//            }
//            RLock lock = redissonClient.getLock(RedisKey.lock + goodIds[i]);
//            //添加分布式锁 加入到集合当中
//            rLocks.add(lock);
//
//            //遍历集合创建value 对象
//
//
//        }


        //加入锁 使用同一个锁
        RLock orderlock = redissonClient.getLock(RedisKey.lock + "order");
        orderlock.lock();

        RTransaction transaction = redissonClient.createTransaction(TransactionOptions.defaults());

        //开启事务

        try {
            // 手动开启事务以免事务为空
//            redisTemplate.setEnableTransactionSupport(true);
            
//            redisTemplate.executePipelined(new SessionCallback<Object>() {
//                @Override
//                public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
//                    return null;
//                }
//            })
            
//            redisTemplate.multi();
            //添加分布式锁
            RLock lock;

            // 事务是否回滚标记
            boolean flag = false;


            for (int i = 0; i < goodIds.length; i++) {

                try {
                    //进行加锁操作
//                    lock.lock();
//                    RLock rLock = rLocks.get(i);
//                    // 加锁
//                    rLock.lock();
                    //获取商品信息
//                    int count = (int) redisTemplate.opsForValue().get(RedisKey.mallGoodCount + goodIds[i]);
                    RBucket<Object> object = transaction.getBucket(RedisKey.mallGoodCount + goodId[i]);
                    Integer count = (Integer) object.get();

                    log.info(goodId[i]+"商品库存"+  count);
                    //判断商品库存是否充足 假设库存小于购买的数量
                    if (count==0||count<num[i]) {
                        System.out.println("商品"+goodId[i]+"不足");
                        //取消事务
                        failGoodId = goodIds[i];

                        // 设计标记位
                        flag=true;
                        //回滚事务
//                        transaction.rollback();
//                        System.out.println("回滚了事务");
//                        redisTemplate.discard();
//                        return Result.fail("商品" + failGoodId + "已经卖完了");
                    } else {
                        // 扣将商品库存
                        //扣除库存
//                        redisTemplate.opsForValue().decrement(RedisKey.mallGoodCount + goodIds[i], num[i]);
                        object.getAndSet(count-num[i]);
                        log.info("剩余库存");
                        // 删除购物车对应的商品
//                        redisTemplate.opsForHash().delete(RedisKey.mallCartKey + userId, goodId[i]);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    System.out.println("并发异常取消事务");
                    transaction.rollback();
//                    redisTemplate.discard();
                    orderlock.unlock();
                    throw  new SystemBusyException();
                }
                finally {

                }

            }
            // 提交事务
//            redisTemplate.exec();

            //判断事务是否回滚
            if (flag){
                // 回滚事务
                transaction.rollback();
                log.info("商品不足，触发回滚");
                // 释放锁
                // 再释放锁 要先保证事务提交成功才能释放锁 不然可能还是读取到假数据
                for (int i=rLocks.size()-1;i>=0;i--){
                    RLock rLock = rLocks.get(i);
                    rLock.unlock();
                }

                return  Result.fail("商品"+failGoodId+"卖完了");

            }

            transaction.commit();
            // 释放锁
            // 再释放锁 要先保证事务提交成功才能释放锁 不然可能还是读取到假数据
//            for (int i=rLocks.size()-1;i>=0;i--){
//                RLock rLock = rLocks.get(i);
//                rLock.unlock();
//            }
            orderlock.unlock();





            //生成多个订单支付
            //先数据库插入数据
            MallOrder mallOrder = new MallOrder();
            BeanUtil.copyProperties(orderParam, mallOrder);

            //设置当前创建时间
            mallOrder.setCreateTime(LocalDateTime.now());
            mallOrder.setUserId(Long.valueOf(userId));
            baseMapper.insert(mallOrder);
            //插入中间表
            for (int i = 0; i < goodIds.length; i++) {
                mallOrderMapper.insertOrder(mallOrder.getOrderId(), Long.valueOf(goodId[i]), num[i]);
            }
            //存入redis 设置过期时间
            redisUtils.set(RedisKey.redisOrderKey + stringBuffer.toString(), mallOrder.getOrderId(), 1800);
            orderParam.setOrderId(mallOrder.getOrderId());


            //删除对应的购物车
            for (int i = 0; i < goodIds.length; i++){
                redisUtils.hdel(RedisKey.mallCartKey+userId,goodId[i]);
            }

            //投递订单队列
            rabbitTemplate.convertAndSend("orderExChange", "orderKey", orderParam);
            return Result.succ("创建订单成功，请在10分钟内完成支付");

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        } finally {

        }







//       //开启redis 事务  并保证 所有操作都在同一个redis 连接上 避免报错
//     boolean result=(boolean)redisTemplate.execute(new SessionCallback() {
//           @Override
//           public Object execute(RedisOperations operations) throws DataAccessException {
//               //开启事务
//               operations.multi();
//               for (int i=0;i<goodIds.length;i++){
//                   int count= (int) operations.opsForValue().get(RedisKey.mallGoodCount+goodIds[i]);
//                   log.info("商品库存"+count);
//                   // 一个商品没有库存 整个购物车结算失败
//                   if (count==0||count<num[i]){
//                       return false;
//                   }
//                   //扣除库存
//                   operations.opsForValue().decrement(RedisKey.mallGoodCount+goodIds[i],num[i]);
//                   // 显示剩余库存
//                   int less= (int) operations.opsForValue().get(RedisKey.mallGoodCount+goodIds[i]);
//                   log.info("剩余库存");
//                   // 扣减购物车
//                   operations.opsForHash().delete(RedisKey.mallCartKey+userId,goodId[i]);
//               }
//               // 提交事务
//               return true;
//           }
//       });
//
//       if (result==false){
//           return Result.fail("商品有商品库存不足，创建订单失败");
//       }
//
//
//
//
//
////
////          //扣除对应的库存
////          for (int i=0;i<goodIds.length;i++){
////
////
////              //开启事务
////              redisTemplate.multi();
////
//////               //
//////              String goodKey=RedisKey.mallGoodKey+goodIds[i];
//////
//////              redisTemplate.watch(goodKey);
////
////
////              //获取当前库存
//////              GoodInfo good = (GoodInfo)redisTemplate.opsForValue().get(RedisKey.mallGoodKey+goodIds[i]);
////
////              int count= (int) redisTemplate.opsForValue().get(RedisKey.mallGoodCount+goodIds[i]);
////
//////              if(good==null){
//////                  return Result.fail("当前商品不存在");
//////              }
////
////              //商品库存 把读写操作来实现原子性实现
//////              log.info("商品库存"+good.getGoodCount());
////              log.info("商品库存"+count);
////
//////              if (good.getGoodCount()==0||good.getGoodCount()<num[i]){
//////
//////                  return Result.succ( good.getGoodName()+"商品库存不足,订单创建失败");
//////              }
////
////              if (count==0||count<num[i]){
////
////                  return Result.succ("商品库存不足,订单创建失败");
////              }
////
////
////
////
//////              good.setGoodCount(good.getGoodCount()-num[i]);
///////             good.setGoodCount(good.getGoodCount()-num[i]);
////
////              //扣除库存
////              redisTemplate.opsForValue().decrement(RedisKey.mallGoodCount+goodIds[i],num[i]);
////              log.info("扣减了");
////
////           int less=  (int) redisTemplate.opsForValue().get(RedisKey.mallGoodCount+goodIds[i]);
////
////              log.info("剩余"+less);
////
////              //删除对应的购物车
////              redisUtils.hdel(RedisKey.mallCartKey+userId,goodId[i]);
////
////
////              //执行事务提交
////              List<Object> exec = redisTemplate.exec();
////
////              if(exec==null||exec.size()==0){
////                  return Result.fail("下单失败");
////              }
////
////          }


    }

    @Override
    public Result getUserOrder(Long userId) throws JsonProcessingException {

        List<OrderInfoVo> userOrder = mallOrderMapper.getUserOrder(userId);


        //把对象转换为json字符串 防止雪花生成的id 显示给前端精度丢失
//        ObjectMapper objectMapper= new ObjectMapper();
//        Object data = objectMapper.writeValueAsString(userOrder);

        return Result.succ(userOrder);
    }


    @Override
    public Result payOrder(Long orderId, Long userId, String goodIds[]) throws IOException, EncodeException {

        //判断订单是否过期
        MallOrder mallOrder = mallOrderMapper.selectById(orderId);
        if (mallOrder.getStatus() == -1) {
            return Result.succ("订单已过期");
        }


        UpdateWrapper<MallOrder> updateWrapper = new UpdateWrapper<>();

        //支付成功
        updateWrapper.set("status", 1);

        updateWrapper.set("pay_time", LocalDateTime.now());

        updateWrapper.set("pay_type", 1);

        updateWrapper.eq("order_id", orderId);

        baseMapper.update(null, updateWrapper);


        //扣除库存增加 销量
        mallGoodMapper.paySuccess(orderId);

        //添加评论表

        List<MallComment> mallComments = new ArrayList<>();
        for (String goodId : goodIds) {
            //创建新的评论表
            MallComment mallComment = new MallComment();
            mallComment.setUserId(userId);
            mallComment.setIsComment(0);
            mallComment.setGoodId(Integer.valueOf(goodId));
            mallComments.add(mallComment);
        }

        //批量添加评论
        mallCommentService.saveBatch(mallComments);


        //通知 在商品页面的用户 谁购买了该商品
        PaySuccessVo paySuccessVo = new PaySuccessVo();

        paySuccessVo.setUserId(userId);
        paySuccessVo.setGoodIds(goodIds);

        //把对象转化为json
        String s = JSONObject.toJSONString(paySuccessVo);
        //群发信息
        WebSocketServe.sendinfo(s, null);


        return Result.succ("支付成功");
    }

    @Override
    public Result ailiPayOrder(Long orderId) {

        UpdateWrapper<MallOrder> updateWrapper = new UpdateWrapper<>();

        //支付成功
        updateWrapper.set("status", 1);
        updateWrapper.set("pay_time", LocalDateTime.now());
        updateWrapper.set("pay_type", 2);
        updateWrapper.eq("order_id", orderId);
        baseMapper.update(null, updateWrapper);


        //扣除库存增加 销量 更改状态
        mallGoodMapper.paySuccess(orderId);

        //查询订单所对应的商品 添加评论记录
        List<Integer> orderGoods = mallOrderMapper.getOrderGoods(orderId);

        MallOrder mallOrder = mallOrderMapper.selectById(orderId);

        //添加评论表

        List<MallComment> mallComments = new ArrayList<>();
        for (Integer goodId : orderGoods) {
            //创建新的评论表
            MallComment mallComment = new MallComment();
            mallComment.setUserId(mallOrder.getUserId());
            mallComment.setIsComment(0);
            mallComment.setGoodId(goodId);
            mallComments.add(mallComment);
        }

        //批量添加评论
        mallCommentService.saveBatch(mallComments);


        return Result.succ("支付成功 ");


    }
}
